#include "./Socket.h"
#include <iostream>

Socket::Socket() {
	this->fdSocket = 0;
	this->activo = false;
}

Socket::Socket(int fd) {
	this->fdSocket = fd;
	if (fd != -1)
		this->activo = true;
	else
		this->activo = false;
}

Socket::~Socket() {
}

int Socket::listen(int puerto, int cantidadCliente) {
	int estado;
	struct sockaddr_in my_addr; // Mi direccion

	fdSocket = ::socket(AF_INET, SOCK_STREAM, 0);
	if (fdSocket == -1)
		return -1;

	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(puerto);
	my_addr.sin_addr.s_addr = INADDR_ANY;
	memset(&(my_addr.sin_zero), '\0', 8);

	estado = bind(fdSocket, (struct sockaddr *) &my_addr,
			sizeof(struct sockaddr));
	if (estado == -1)
		return -1;

	estado = ::listen(fdSocket, cantidadCliente);
	if (estado == -1)
		return -1;

	this->activo = true;
	return estado;
}

Socket* Socket::accept() {
	struct sockaddr_in their_addr;
	int size;
	int socketConexion;

	size = sizeof(struct sockaddr_in);
	socketConexion = ::accept(fdSocket, (struct sockaddr *) &their_addr,
			(socklen_t*) &size);

	if (socketConexion == -1)
		return NULL;

//	std::cout << "Se conecto: "<< inet_ntoa(their_addr.sin_addr) << std::endl;
	return new Socket(socketConexion);
}

int Socket::recv(char* buf, int size) {
	return ::recv(this->fdSocket, buf, size, 0);
}

bool Socket::recvToString(std::string& buffer) {
	int size = 255;
	char c_buffer[255];
	int bytesRecibidos = 0;
	//buffer.clear();

	bytesRecibidos = ::recv(this->fdSocket, c_buffer, size, 0);
	c_buffer[bytesRecibidos] = '\0';

	if (bytesRecibidos == 0) // Se deconecto el cliente..
		return false;

	buffer.append(c_buffer);
	return true;

}

int Socket::send(const void* buffer, int size) {
	if (this->activo)
		return ::send(this->fdSocket, buffer, size, 0);
	else
		return -1;
}

unsigned long Socket::obtenerIP(const char* host) const {
	unsigned long direccion;

	direccion = inet_addr(host);

	if (direccion == INADDR_NONE) {
		hostent* h = gethostbyname(host);
		if (!h)
			direccion = INADDR_NONE;
		else
			direccion = *((unsigned long*) h->h_addr);
	}
	return direccion;
}

bool Socket::connect(const std::string &host, unsigned int puerto) {
	sockaddr_in direccionServer;
	this->fdSocket = socket(AF_INET, SOCK_STREAM, 0);

	if (this->fdSocket == -1)
		return false;

	memset(&direccionServer, 0, sizeof(direccionServer));
	direccionServer.sin_family = AF_INET;

	direccionServer.sin_addr.s_addr = obtenerIP(host.c_str());

	if (direccionServer.sin_addr.s_addr == INADDR_NONE)
		return false;

	direccionServer.sin_port = htons(puerto);

	if (::connect(this->fdSocket, (sockaddr*) &direccionServer,
			sizeof(direccionServer)) == -1)
		return false;

	this->activo = true;
	return true;
}

int Socket::shutdown() {
	this->activo = false;
	return ::shutdown(this->fdSocket, SHUT_RDWR);
}

void Socket::close() {
	this->activo = false;
	::close(this->fdSocket);
}

bool Socket::estaActivo() {
	return this->activo;
}
